#include <rtthread.h>
#include <rtdevice.h>
#include <stdlib.h>
#include <stdio.h>
#include <board.h>
#include "user4g.h"
#include "userserial.h"
#include "tcpclient.h"
#include "userled.h"
#include "uconfig.h"
#include "userlora.h"
#include "userport.h"
#include <dfs_fs.h>
#include "dfs_posix.h"	

#define DBG_TAG "serial"
#define DBG_LVL DBG_INFO
#include <rtdbg.h>

#define LORA_M0_PIN	GET_PIN(D, 0)
#define LORA_M1_PIN	GET_PIN(D, 1)
#define SAMPLE_UART_NAME       "uart5"
#define maxbufflen    64
#define maxFramewait  200
#define cmdfind  "A1"
#define cmdread  "A2"
#define cmdok    "80OK"
#define cmderror "80ERROR"
#define cmdsettime "SETRTC"

/* 用于接收消息的信号量 */
static struct rt_semaphore serial_rx_sem;

char ES_sendbuff[9];
static rt_device_t serial;


static char STxbuff[maxbufflen];
static char SRxbuff[maxbufflen];
static char serialstate;
T_slavedevicememory loardevicebuff[MAXloramemorydepth];
static PT_slavedevicememory ptcurrentmemory=loardevicebuff;
PT_slavedevicememory ptmemoryhead=loardevicebuff;
T_slavedevicememory willsendbuff;
static int currentindex=0;
static int fileindex=0;

char *CheckSum(char *buf, int len,char *string) 
{ 
    char i, ret = 0;  
    memset(string,0,2);
    for(i=0; i<len; i++)
    {
        ret += *(buf++);
    }
		sprintf(string,"%02X",ret);
    return 0;
}

/****************************************************************************/
/****************************************************************************/
static rt_err_t uart_input(rt_device_t dev, rt_size_t size)/* 接收数据回调函数 */
{
    rt_sem_release(&serial_rx_sem);
    return RT_EOK;
}

/****************************************************************************/
/****************************************************************************/
static int serialRCV(char *buff)
{
	rt_err_t  resultA=RT_ERROR;
	rt_err_t  resultB=RT_ERROR;
	int rcvstate=RT_ERROR;
	char *startbuff=buff;
	char string[2]={0};
	
	if(serialstate!=Sidle) 
		    return RT_ERROR;
	serialstate=Srcv;
	memset(buff,0,maxbufflen);
	resultA=rt_sem_take(&serial_rx_sem, MAX_FrameWait_TIMEOUT);
  if(resultA==RT_EOK)
		{ 
			  while(1)
			  {	
				 while (rt_device_read(serial, -1, buff, 1) != 1)
						{															
							resultB=rt_sem_take(&serial_rx_sem, maxFramewait);							
							 if(resultB!=RT_EOK)
							  {  
									 serialstate=Sidle;
									 CheckSum(startbuff, strlen(startbuff)-2,string);
									 if(string[0]==startbuff[strlen(startbuff)-2] && string[1]==startbuff[strlen(startbuff)-1] )
									    rcvstate=RT_EOK;									 
                   return rcvstate;								 
							  }
							buff++;							
						}								
			  }	
		}
		else
		{
			serialstate=Sidle;
			rcvstate=RT_ETIMEOUT;	
      return rcvstate;				
		}
}


/****************************************************************************/
/****************************************************************************/
static int serialSEND(char *buff ,char len)
{ 
	if(serialstate!=Sidle) 
	return 0;
	serialstate=Ssend;
	CheckSum(buff,len,&buff[len]);
	NETLORALED_ON();
	rt_device_write(serial, 0, buff, len+2);
	NETLORALED_OFF();
	serialstate=Sidle;
	if(strstr(buff,cmdok)!=NULL || strstr(buff,cmderror)!=NULL|| strstr(buff,cmdsettime)!=NULL)
		  return 0;
	return serialRCV(SRxbuff);
}

/****************************************************************************/
/****************************************************************************/
static int getbufflen(void)
{
	struct stat StatInfo;
	int rc;
	rc = stat(datafile, &StatInfo);
	if(rc < 0){
			LOG_E("Get file information(%s)fail\n", datafile);
			return -RT_ERROR;
	}	
	LOG_I(" file size=%d\n", StatInfo.st_size);	
	return StatInfo.st_size/sizeof(T_slavedevicememory);
}
/****************************************************************************/
/****************************************************************************/
static void sack(char *spid,char *ptd)
{
	memset(STxbuff,0,sizeof(STxbuff));
	memcpy(STxbuff,spid,strlen(spid));
	memcpy(&STxbuff[strlen(spid)],ptd,strlen(ptd));
	serialSEND(STxbuff ,strlen(STxbuff));
}
/************************************************************************************/
/************************************************************************************/
int readFromSpiflash(void)
{
	int fd, size,i;
	int num,numA=0;
	PT_slavedevicememory ptd=&willsendbuff;
#define readlen sizeof(T_slavedevicememory)
	char buff[readlen];
  num=getbufflen();
	if(num<=0)
		return 0;

	fd = open(datafile,O_RDONLY|O_CREAT);
	if (fd< 0){
	  return 0;
	}
	lseek(fd, fileindex*sizeof(T_slavedevicememory), SEEK_SET);
	for(i=0;i<num;i++){
			memset(buff,0,sizeof(buff));
			size = read(fd, buff,readlen);
			if(size>0){
				sscanf(buff,"%7s%1s%8s%3s%12s",ptd->sid,ptd->scode,ptd->pulse,ptd->duration,ptd->time);
				if(ReportIncident(ptd,ES_d,3000,0)==RT_EOK){
					numA++;
					continue;
				}		       
			}
	}
	close(fd);
	if(num==numA){
		fileindex=0;
	  unlink(datafile);
  }
	else {
		fileindex=i;
  }
	return 0;
}

/************************************************************************************/
/************************************************************************************/
int singleWriteToSpiflash(PT_slavedevicememory pts)
{
	int fd;
	char pbuff[31];
	
	fd = open(datafile,O_WRONLY|O_CREAT|O_APPEND);
	if (fd< 0){
		return 0;
	}
	lseek(fd, 0, SEEK_END);
	memset(pbuff,0,sizeof(pbuff));
	memcpy(pbuff,pts->sid,sizeof(pts->sid));
	memcpy(&pbuff[7],pts->scode,sizeof(pts->time));
	memcpy(&pbuff[8],pts->pulse,sizeof(pts->pulse));
	memcpy(&pbuff[16],pts->duration,sizeof(pts->duration));
	memcpy(&pbuff[19],pts->time,sizeof(pts->time));				
	write(fd, pbuff, sizeof(pbuff));
	close(fd);
}
/************************************************************************************/
/************************************************************************************/
static int multiWriteToSpiflash(PT_slavedevicememory ptlast)
{
	int fd,i;
  PT_slavedevicememory ptstart=loardevicebuff;
	char pbuff[35];
	int ch=ptlast-ptstart;
	
		fd = open(datafile,O_WRONLY|O_CREAT|O_APPEND);
		if (fd< 0){
			return 0;
		}
		lseek(fd, 0, SEEK_END);
		if (ch>0) {
		  for(i=0;i<ch;i++){
					memset(pbuff,0,sizeof(pbuff));
					memcpy(pbuff,ptstart->sid,sizeof(ptstart->sid));
				  memcpy(&pbuff[7],ptstart->scode,sizeof(ptstart->time));
				  memcpy(&pbuff[8],ptstart->pulse,sizeof(ptstart->pulse));
				  memcpy(&pbuff[16],ptstart->duration,sizeof(ptstart->duration));
					memcpy(&pbuff[19],ptstart->time,sizeof(ptstart->time));				
					write(fd, pbuff, strlen(pbuff));
					ptstart++;
			}		
    ptcurrentmemory=loardevicebuff;
    currentindex=0;	
	}	
	
		close(fd);
	  return RT_EOK;
}


/************************************************************************************/
/************************************************************************************/
//static void buftomemory(PT_slavedevicememory start,int len)
//{
//	int i;
//	if(len>0){
//		 for(i=0;i<len;i++) {			 
//			 memcpy(pt4Gindex,start,sizeof(T_slavedevicememory));
//			 pt4Gindex++;
//       if(pt4Gindex==&buff4Gmemory[MAX4gmemorydepth]) {
//				  multiWriteToSpiflash();
//				  pt4Gindex=buff4Gmemory;
//				  continue ;
//			  }
//			 start++;
//				if(start==&loardevicebuff[MAXloramemorydepth])
//				{
//					start=loardevicebuff;
//				}      				
//		}		 	
//	}
//}

/****************************************************************************/
/****************************************************************************/
void gunstateread(char index)
{
	static char sflag[6]={0};
	static char laststate[MAX_salvedevice][6];
	char chi;
	char string[1]={0};
  PT_LoraSlave pts=&Devicetab_salve;

	memset(ES_sendbuff,0,sizeof(ES_sendbuff));
	if(sflag[index]==0){

			memset(ES_sendbuff,0,sizeof(ES_sendbuff));
			memcpy(ES_sendbuff,pts->codetab[index],7);
				for(chi=0;chi<6;chi++){
					ES_sendbuff[7]=chi+1;
					memcpy(string,&pts->gunstate[index][chi],1);
					ES_sendbuff[8]=atoi(string);
				  if(ReportIncident(ES_sendbuff,ES_s,5000,0)!=RT_EOK){
						continue;
				  }					
				}
				memcpy(&laststate[index],pts->gunstate[index],6);	
		sflag[index]=1;	
	}
	else{
			 memset(ES_sendbuff,0,sizeof(ES_sendbuff));
			 memcpy(ES_sendbuff,pts->codetab[index],7);
		   if(memcmp(pts->gunstate[index],laststate[index],6)!=0){
			    for(chi=0;chi<6;chi++) {
					   if(pts->gunstate[index][chi]!=laststate[index][chi]){
								 ES_sendbuff[7]=chi+1;
								 memcpy(string,&pts->gunstate[index][chi],1);
								 ES_sendbuff[8]=atoi(string);
								 ReportIncident(ES_sendbuff,ES_s,3000,0);
							   laststate[index][chi]=pts->gunstate[index][chi];															  
						 }
					}
			 }
	}
}


/****************************************************************************/
/****************************************************************************/

static int CallSlaveDevice(PT_LoraSlave ptab,char *spcmd,char index)
{
	char buffA[7];
	char buffB[2];
  char buffC[8];
  char buffD[3];
  char buffE[3];
  char buffF[12];
	char *sendid= ptab->codetab[index];
	char *ptindex=ptab->gunstate[index];

	int chi=0;
	
	memset(buffA,0,sizeof(buffA));
  memset(buffB,0,sizeof(buffB));
	memset(buffC,0,sizeof(buffC));
  memset(buffD,0,sizeof(buffD));  
	memset(buffE,0,sizeof(buffE));
  memset(buffF,0,sizeof(buffF));  
	memset(STxbuff,0,sizeof(STxbuff));
	memcpy(STxbuff,sendid,strlen(sendid));
	memcpy(&STxbuff[strlen(sendid)],spcmd,strlen(spcmd));
	if(serialSEND(STxbuff ,strlen(STxbuff))==RT_EOK)
	{
		sack(sendid,cmdok);
		if(strstr(SRxbuff,cmdfind)){
				sscanf(SRxbuff, "%7s%2s%6s%s",buffA,buffB,buffC,buffD);
				if(memcmp(buffA,sendid,strlen(sendid))==0){
						if(memcmp(ptindex,buffC,6)!=0){
							 memset(ptindex,0,6);
							 memcpy(ptindex,buffC,6);							 
						} 
						if(memcmp(buffB,spcmd,strlen(spcmd))==0){
							 chi=strlen(buffD);
						   if(chi>=3){
								 buffD[chi-1]=0;
								 buffD[chi-2]=0;
								 return atol(buffD);
							 }else {
								 return 0;
							 }							 
							 
						}
				}
		  }			
			else if(strstr(SRxbuff,cmdread)){
		      memcpy(buffA,SRxbuff,7);
				  memcpy(buffB,&SRxbuff[9],1);
				  memcpy(buffC,&SRxbuff[10],8);
				  memcpy(buffD,&SRxbuff[18],3);
				  memcpy(buffE,&SRxbuff[21],3);
				  memcpy(buffF,&SRxbuff[24],12);
					if(memcmp(buffA,sendid,strlen(sendid))==0){
//							 if(currentindex>=MAXloramemorydepth){		
//                  if(multiWriteToSpiflash(ptcurrentmemory)!=RT_EOK) {
//										LOG_E("write into memory fial and data number=%d",currentindex);
//										ptcurrentmemory=loardevicebuff;
//								    currentindex=0;
//									}																			
//									memset(ptcurrentmemory,0,sizeof(T_slavedevicememory)*MAXloramemorydepth);	
//							  }
               memset(ptcurrentmemory,0,sizeof(T_slavedevicememory));								
							 memcpy(ptcurrentmemory->sid,buffA,sizeof(ptcurrentmemory->sid));								
							 memcpy(ptcurrentmemory->scode,buffB,sizeof(ptcurrentmemory->scode));
							 memcpy(ptcurrentmemory->pulse,buffC,sizeof(ptcurrentmemory->pulse));
							 memcpy(ptcurrentmemory->duration,buffD,sizeof(ptcurrentmemory->duration));
               memcpy(ptcurrentmemory->time,buffF,sizeof(ptcurrentmemory->time));
						   if(DataParameter4G.Devicestate==ON_LINE)  			
				           ReportIncident(ptcurrentmemory, ES_d,3000,1);
				       else
					         singleWriteToSpiflash(ptcurrentmemory);
               return RT_EOK;              						
						}
						return -RT_ERROR;						
			}
	}
	else
	{
		sack(sendid,cmderror);
		return -RT_ERROR;
	}
  return -RT_ERROR;
}



/****************************************************************************/
/****************************************************************************/
void serialportinit()
{
		rt_pin_mode(LORA_M0_PIN, PIN_MODE_OUTPUT);	
    rt_pin_mode(LORA_M1_PIN, PIN_MODE_OUTPUT);	
		rt_pin_write(LORA_M0_PIN, PIN_LOW);
		rt_pin_write(LORA_M1_PIN, PIN_LOW);		
}
/****************************************************************************/
/****************************************************************************/
int uartInit(rt_uint32_t baud,rt_uint32_t Parity)
{
    rt_err_t ret = RT_EOK;
    char uart_name[RT_NAME_MAX];
		struct serial_configure config = RT_SERIAL_CONFIG_DEFAULT;  
	
    rt_strncpy(uart_name, SAMPLE_UART_NAME, RT_NAME_MAX);     
    serial = rt_device_find(uart_name);					
    if (!serial)
			{
				rt_kprintf("find serial %s failed!\n", uart_name);
				return RT_ERROR;
			}
		config.baud_rate = baud;        
		config.data_bits = 8;          
		config.stop_bits = STOP_BITS_1;           
		config.bufsz     = 128;                   
		config.parity    = Parity;  
	  rt_device_control(serial, RT_DEVICE_CTRL_CONFIG, &config);

    rt_sem_init(&serial_rx_sem, "serial_rx", 0, RT_IPC_FLAG_FIFO);			

    if (!rt_device_open(serial, RT_DEVICE_OFLAG_RDWR | RT_DEVICE_FLAG_INT_RX)) 
			{
        rt_device_set_rx_indicate(serial, uart_input);
      } 

		serialportinit();
	  serialstate=Sidle;
    return ret;
}

/****************************************************************************/
/****************************************************************************/
static void utctimebroad(void)
{
	char string[12]={0};
	memset(string,0,sizeof(string));
	memset(STxbuff,0,sizeof(STxbuff));
	getrcttime(string);
	sprintf(STxbuff,"SETRTC:%12s",string);
	serialSEND(STxbuff ,strlen(STxbuff));
}
/****************************************************************************/
/****************************************************************************/
static void Readevice(PT_LoraSlave ptab)
{
  char i;
	int ch=0;
	if(ptab->deviceNumber>0) {
		for(i=0;i<ptab->deviceNumber;i++) {
				ch=CallSlaveDevice(ptab,cmdfind,i);			
				while(ch>0){
					   rt_thread_mdelay(3000);
             if(CallSlaveDevice(ptab,cmdread,i)==RT_EOK) {
							  ch--;
							  rt_thread_mdelay(MAX_FrameWait_TIMEOUT);
						 }
             else	{
							  rt_thread_mdelay(MAX_FrameWait_TIMEOUT);
							  if(CallSlaveDevice(ptab,cmdread,i)==RT_EOK){
								    ch--;
						      }
							  else  {
									LOG_E("probe two (%s) but no recv or recv error !\n", ptab->codetab[i]);
									break;
							  }
						 }
          						 
				 }
				rt_thread_mdelay(2000);
        gunstateread(i);							 
		}			     
	}

}
/****************************************************************************/
/****************************************************************************/

void VserialTX_task(void *parameter)
{ 
	int timecount=0;
	uartInit(BAUD_RATE_9600,0);

  rt_event_recv(EVENTDevic,EVENT_SocketConnect|EVENT_NTPOK,RT_EVENT_FLAG_AND,RT_WAITING_FOREVER,RT_NULL);
	utctimebroad();
	while(1)
	{	 
    if(rt_event_recv(EVENTDevic,EVENT_Mode_lora,RT_EVENT_FLAG_AND,0,RT_NULL)==RT_EOK){
				Readevice(&Devicetab_salve);
		    rt_thread_mdelay(4000);
			  timecount++;
		}
		else{
		   rt_thread_mdelay(60000);
			 timecount++;
		}		
		if(timecount>=5){
		  timecount=0;		
      if(rt_event_recv(EVENTDevic,EVENT_SocketConnect,RT_EVENT_FLAG_AND,0,RT_NULL)==RT_EOK)
			    readFromSpiflash();
			if(rt_event_recv(EVENTDevic,EVENT_Mode_lora,RT_EVENT_FLAG_AND,0,RT_NULL)==RT_EOK){
					utctimebroad();
          rt_thread_mdelay(4000);				
			}		
		}
	}
}
